package ws.very.util.lang

import java.io.FileOutputStream
import java.net.URL
import java.util.zip.GZIPInputStream
import java.nio.channels.Channels
import java.io.File
import java.io.InputStream
import java.io.IOException
import java.io.OutputStreamWriter
import java.io.Writer
import ShortTypes._
import SysPropCookies._
object IOs {

  /**
   * 使用URL需要注意特别编码问题 比如中文 URLEncoder.encode(w,"utf-8")
   */
  object net { //FIXME:https?
    def download(url: URL, target: File, connTimeout: Int = 5000, readTimeout: Int = 5000) =
      urlChannelWithGzip(url, connTimeout, readTimeout) { i =>
        Using(new FileOutputStream(target)) { o =>
          o.getChannel().transferFrom(Channels.newChannel(i), 0, Long.MaxValue)
          target
        }
      }()

    def urlChannelWithGzip[R](url: URL, connTimeout: Int = 5000, readTimeout: Int = 5000)(otherFn: InputStream => R)(gzipFn: GZIPInputStream => R = otherFn): R = {
      val conn = url.openConnection()
      conn.setConnectTimeout(connTimeout)
      conn.setReadTimeout(readTimeout)
      Using(conn.getInputStream()) { i =>
        val encoding = conn.getHeaderField("Content-Encoding")
        if (encoding != null && encoding.toLowerCase() == "gzip")
          Using(new GZIPInputStream(i)) { ii =>
            gzipFn(ii)
          }
        else
          otherFn(i)
      }
    }
    def readUrlBytes(url: URL, connTimeout: Int = 5000, readTimeout: Int = 5000) =
      urlChannelWithGzip(url, connTimeout, readTimeout) { i =>
        bytesFrom(i)
      }()

  }
  def makeParentDir(f: File) = {
    if (!f.getParentFile.exists)
      f.getParentFile.mkdirs
    f
  }
  @deprecated
  private def bytesFrom(input: InputStream): Array[Byte] =
    Stream.continually(input.read).takeWhile(-1 !=).map(_.toByte).toArray

  @deprecated
  def toByteArray(input: InputStream) = Using(input) { bytesFrom _ }

  //FIXME:未测试 用于替代bytesFrom的内存问题
  private def bytes(input: InputStream) = {
    val cnt = input.available
    val bytes = Array.ofDim[Byte](cnt)
    input.read(bytes)
    bytes
  }

  def Utf8Writer = chatsetWriter("utf-8") _
  def SysWriter = chatsetWriter(sysProp.fileEncoding) _
  private def chatsetWriter(charset: S)(file: File, append: B = false) = new OutputStreamWriter(new FileOutputStream(file, append), charset)

  def toBytesAndClose(input: InputStream) = Using(input) { in =>
    bytes(in)
  }

}

trait RichIO {
  implicit class RichWrite(write: Writer) {
    def writeln(line: A*) = write.write(line.mkString("\t") + "\n")
  }

}